home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-12-17 | 49.8 KB | 2,373 lines |
- Newsgroups: comp.sources.misc
- X-UNIX-From: mrapple@quack.sac.ca.us
- organization: The Duck Pond, Stockton, CA
- summary: This is sort of a beta release.
- subject: v15i101: Z-80 emulator in C, with CP/M BIOS (part 1/2)
- from: mrapple@quack.sac.ca.us (Nick Sayer)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 15, Issue 101
- Submitted-by: mrapple@quack.sac.ca.us (Nick Sayer)
- Archive-name: upm/part01
-
- #!/bin/sh
- # This is a shell archive (shar 3.24)
- # made 10/31/1990 19:28 UTC by mrapple@quack
- # Source directory /files/users/mrapple/upm
- #
- # existing files WILL be overwritten
- #
- # This is part 1 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 853 -rw-r--r-- Makefile
- # 717 -rw-r--r-- README
- # 1625 -rw-r--r-- README.upm
- # 5553 -rw-r--r-- bios.c
- # 8597 -rw-r--r-- debug.c
- # 462 -rw-r--r-- io_ask.c
- # 255 -rw-r--r-- io_mem.c
- # 373 -rw-r--r-- lh.c
- # 1262 -rw-r--r-- loadhex.c
- # 1062 -rw-r--r-- makedrive.c
- # 9809 -rw-r--r-- udbg.c
- # 6850 -rw-r--r-- upm.c
- # 1744 -rw-r--r-- upm.h
- # 27243 -rw-r--r-- z80.c
- # 1672 -rw-r--r-- z80.h
- # 16492 -rw-r--r-- z80_cbed.c
- #
- if touch 2>&1 | fgrep '[-amc]' > /dev/null
- then TOUCH=touch
- else TOUCH=true
- fi
- if test -r shar3_seq_.tmp; then
- echo "Must unpack archives in sequence!"
- next=`cat shar3_seq_.tmp`; echo "Please unpack part $next next"
- exit 1
- fi
- # ============= Makefile ==============
- echo "x - extracting Makefile (Text)"
- sed 's/^X//' << 'SHAR_EOF' > Makefile &&
- Xz80.o: z80.h
- Xz80_cbed.o: z80.h
- X
- XZOBJS = z80.o z80_cbed.o
- XIFILES = z80.h
- X
- XCFLAGS = -O
- X
- Xall: upm debug dumbrun makedrive dbg
- X
- Xdebug: $(ZOBJS) io_ask.o debug.o loadhex.o
- X $(CC) $(CFLAGS) $(ZOBJS) io_ask.o debug.o loadhex.o -o debug
- X
- Xdbg: $(ZOBJS) io_ask.o dbg.o loadhex.o
- X $(CC) $(CFLAGS) $(ZOBJS) io_ask.o dbg.o loadhex.o -o dbg
- X
- Xdumbrun: $(ZOBJS) io_ask.o dumbrun.o
- X $(CC) $(CFLAGS) $(ZOBJS) io_ask.o dumbrun.o -o dumbrun
- X
- Xbios.o: z80.h
- Xdebug.o: z80.h
- Xio_ask.o: z80.h
- Xio_mem.o: z80.h
- Xloadhex.o: z80.h
- Xlh.o: z80.h
- Xudbg.o: z80.h
- X
- Xupm: $(ZOBJS) io_mem.o upm.o loadhex.o bios.o udbg.o
- X $(CC) $(CFLAGS) $(ZOBJS) io_mem.o upm.o loadhex.o bios.o udbg.o -o upm
- X
- Xmakedrive: makedrive.c
- X $(CC) $(CFLAGS) makedrive.c -o makedrive
- X
- Xinitdisk: initdisk.c
- X $(CC) $(CFLAGS) initdisk.c -o initdisk
- X
- X$(ZOBJS): z80.h
- X
- Xclean:
- X rm -f upm debug dumbrun makedrive initdisk *.o
- SHAR_EOF
- $TOUCH -am 0928182190 Makefile &&
- chmod 0644 Makefile ||
- echo "restore of Makefile failed"
- set `wc -c Makefile`;Wc_c=$1
- if test "$Wc_c" != "853"; then
- echo original size 853, current size $Wc_c
- fi
- # ============= README ==============
- echo "x - extracting README (Text)"
- sed 's/^X//' << 'SHAR_EOF' > README &&
- XSince emulating a CPU is a fairly memory intensive thing to do,
- Xit's unlikely that the Z-80 emulator code will require any reworking
- Xto fit your needs. There is an option you need to set, though. Two
- Xfiles are included to handle I/O instructions. io_mem.c implements
- Xa 256 byte RAM on the I/O space. io_ask.c prompts the console
- Xfor input and prints output writes.
- X
- XYou also have a couple choices for main():
- X
- Xdebug.c is a debugger. This debugger is intended primarily to debug
- Xthe interpreter itself rather than debug z-80 code.
- X
- Xupm.c implements CP/M on top of the emulator. See README.upm
- X
- XMany thanks to Mark W. Eichin for his help in debugging some
- Xof my truely nasty code during Alpha-testing. Truely a saint.
- X
- SHAR_EOF
- $TOUCH -am 1031111990 README &&
- chmod 0644 README ||
- echo "restore of README failed"
- set `wc -c README`;Wc_c=$1
- if test "$Wc_c" != "717"; then
- echo original size 717, current size $Wc_c
- fi
- # ============= README.upm ==============
- echo "x - extracting README.upm (Text)"
- sed 's/^X//' << 'SHAR_EOF' > README.upm &&
- XThe BIOS is implemented like this:
- X
- Xxx00: 76 C9 00 76 C9 00 76 C9 00......
- X
- XFor the non-z80-literate, that is a series of HALT and RETurn from
- Xsubroutine statements. HALT instructions return control to the calling
- X(c program) routine that started the Z-80 running in the first place.
- XBy dividing the low 8 bits of the PC by 3, we can find out what BIOS
- Xroutine the caller wanted, do it in C, then return.
- X
- Xupm takes various paramaters either on the command line or in
- X~/.upmrc. If specified, command line paramaters take precedence over
- X.upmrc options. Options are in the form of dev:file, where dev is
- XA-O, for disk devices, or TY, LP, PT, U1 or U2, for alternate physical
- Xdevices. The files specified are attached to the coresponding disks or
- Xphysical devices. The above identifiers corespond to these CP/M physical
- Xdevices:
- X
- XTY TTY:
- XLP LPT:
- XPT PTP: PTR:
- XU1 UC1: UL1: UP1: UR1:
- XU2 UP2: UR2:
- X
- XThe CRT: device is permanently assigned to stdin/stdout. stdin/stdout
- Xare set to RAW mode, to make all keys work. The last BIOS jump table
- Xentry is non-standard, and causes the CP/M system to halt and control
- Xreturn to unix. The CP/M program EXIT.COM will do this.
- X
- XAs usual, the BAT: device is a combination of CRT: and LPT:
- X
- XThe default I/O byte assigns as follows:
- X
- XCON:=CRT:
- XRDR:=PTP:
- XPUN:=PTR:
- XLST:=LPT:
- X
- XA typical command line might say:
- X
- X% upm a:cpm.adrive lp:printer_file pt:copy_file
- X
- XThe device identifiers may be in upper-case, but the files, of course,
- Xwill be literal-cased.
- X
- XAll device files except LP: will be fopen()ed "r+". LP: will be
- Xfopen()ed "w".
- X
- XAny device not specifically assigned will act like /dev/null.
- SHAR_EOF
- $TOUCH -am 1031112690 README.upm &&
- chmod 0644 README.upm ||
- echo "restore of README.upm failed"
- set `wc -c README.upm`;Wc_c=$1
- if test "$Wc_c" != "1625"; then
- echo original size 1625, current size $Wc_c
- fi
- # ============= bios.c ==============
- echo "x - extracting bios.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > bios.c &&
- X/*
- X
- Xbios.c - CP/M BIOS in C
- X
- X(C) MCMXM - Nick Sayer - All rights reserved.
- X
- XSee COPYRIGHT file for more details.
- X
- X*/
- X
- X#include <stdio.h>
- X#include "z80.h"
- X#include "upm.h"
- X
- X#include <sys/ioctl.h>
- X
- X#define IO_BYTE 3
- X
- XWORD trk,sec,dma,dsk;
- X
- Xchar cold_flag=0;
- X
- X/*
- X
- XOur Z-80 BIOS is just HALT, RET, NOP, HALT, RET, NOP..... We find out
- Xwhich BIOS jump it is by dividing the LSB of PC by 3.
- X
- XTHIS PRESUMES BIOS BEGINS ON AN EVEN PAGE BOUNDARY. This is a pretty
- Xgood assumption.
- X
- XBIOS Memory map:
- X
- X0000 - jump table
- X0080 - DIRBUF
- X0100 - disk buffers - this set up in upm.c
- X
- XIt is up to upm.c to set up the disk buffers as necessary for
- Xdifferent size devices, and set up the pointers in diskbufs[].
- X
- X*/
- X
- Xchar bios()
- X{
- X register char bios_call;
- X
- X bios_call=(PC&0xff)/3;
- X PC++; /* Skip past the HALT */
- X
- Xif(debugflag) printf("\tBios! - %d from %x\n\r",bios_call,PC);
- X
- X switch(bios_call)
- X {
- X case 0:cold_boot(); /* DON'T break... we WANT to fall into warm boot! */
- X case 1:warm_boot();
- X break;
- X case 2:stat_con();
- X break;
- X case 3:read_con();
- X break;
- X case 4:write_con();
- X break;
- X case 5:write_lst();
- X break;
- X case 6:write_pun();
- X break;
- X case 7:read_rdr();
- X break;
- X case 8:home_dsk();
- X break;
- X case 9:sel_dsk();
- X break;
- X case 10:set_trk();
- X break;
- X case 11:set_sec();
- X break;
- X case 12:set_dma();
- X break;
- X case 13:read_dsk();
- X break;
- X case 14:write_dsk();
- X break;
- X case 15:stat_lst();
- X break;
- X case 16:sec_trans();
- X break;
- X case 30:shell_escape();
- X break;
- X case 31:quit(); return 1;
- X default:
- X printf("unhandled bios call %d\n\r",bios_call);
- X debugit();
- X }
- X
- X return 0;
- X}
- X
- Xquit()
- X{
- X}
- X
- Xshell_escape()
- X{
- X debugit();
- X}
- X
- Xcold_boot()
- X{
- X
- X real_z80_mem[IO_BYTE]=0x95; /* CRT, PUN, RDR, LPT */
- X real_z80_mem[0]=0xC3;
- X real_z80_mem[1]=0x03;
- X real_z80_mem[2]=(ccp_start>>8)+8+0xe; /* First page of BIOS */
- X real_z80_mem[5]=0xC3;
- X real_z80_mem[6]=0x06;
- X real_z80_mem[7]=(ccp_start>>8)+8; /* First page of BDOS */
- X printf("\n\r\n\rCP/M Ver 2.2\n\rCopyright Digital Research, Inc.\n\r");
- X printf("UP/M Version 1.0B\n\rCopyright Nick Sayer\n\r\n\r");
- X cold_flag++;
- X
- X}
- X
- Xwarm_boot()
- X{
- X register WORD i;
- X
- X for(i=0;i<SIZE_CCP_IMAGE;i++)
- X real_z80_mem[i+ccp_start]=ccp_image[i];
- X
- X if (cold_flag)
- X {
- X cold_flag=0;
- X PC=ccp_start;
- X }
- X else
- X PC=ccp_start+3;
- X
- X BC=0;
- X debugit();
- X}
- X
- Xstat_con()
- X{
- X FILE *which;
- X int ret;
- X
- X switch (real_z80_mem[IO_BYTE]&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=stdin; break;
- X case 2:which=stdin; break;
- X case 3:which=devices[F_U1]; break;
- X }
- X
- X ioctl(fileno(which),FIONREAD,&ret);
- X AF=(AF&0xff)|(ret?0xff00:0);
- X/* */
- X/* if(!ret) AF |= FLAG_Z; else AF &= ~FLAG_Z; */
- X AF |= FLAG_Z;
- X
- X}
- X
- Xread_con()
- X{
- X FILE *which;
- X
- X switch (real_z80_mem[IO_BYTE]&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=stdin; break;
- X case 2:which=stdin; break;
- X case 3:which=devices[F_U1]; break;
- X }
- X if (which==NULL)
- X {
- X AF&=0xff;
- X return;
- X }
- X AF=(AF&0xff)|(getc(which)<<8);
- X}
- X
- Xwrite_con()
- X{
- X FILE *which;
- X
- X switch(real_z80_mem[IO_BYTE]&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=stdout; break;
- X case 2:write_lst(); which=stdout; break;
- X case 3:which=devices[F_U1]; break;
- X }
- X if (which!=NULL)
- X putc(BC&0xff,which);
- X}
- X
- Xstat_lst()
- X{
- X FILE *which;
- X
- X/*
- X switch((real_z80_mem[IO_BYTE]>>6)&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=stdout; break;
- X case 2:which=devices[F_LP]; break;
- X case 3:which=devices[F_U1]; break;
- X }
- X
- XUnder unix, writing is always fine.
- X
- X*/
- X AF|=0xff00;
- X}
- X
- Xwrite_lst()
- X{
- X FILE *which;
- X
- X switch((real_z80_mem[IO_BYTE]>>6)&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=stdout; break;
- X case 2:which=devices[F_LP]; break;
- X case 3:which=devices[F_U1]; break;
- X }
- X if (which!=NULL)
- X putc(BC&0xff,which);
- X}
- X
- Xwrite_pun()
- X{
- X FILE *which;
- X
- X switch((real_z80_mem[IO_BYTE]>>4)&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=devices[F_PT]; break;
- X case 2:which=devices[F_U1]; break;
- X case 3:which=devices[F_U2]; break;
- X }
- X if (which!=NULL)
- X putc(BC&0xff,which);
- X}
- X
- Xread_rdr()
- X{
- X FILE *which;
- X
- X switch((real_z80_mem[IO_BYTE]>>2)&0x3)
- X {
- X case 0:which=devices[F_TY]; break;
- X case 1:which=devices[F_PT]; break;
- X case 2:which=devices[F_U1]; break;
- X case 3:which=devices[F_U2]; break;
- X }
- X if (which==NULL)
- X {
- X AF&=0xff;
- X return;
- X }
- X AF=(AF&0xff)|(getc(which)<<8);
- X}
- X
- Xhome_dsk()
- X{
- X bioslog("home disk\n\r");
- X trk = 0;
- X}
- X
- Xsec_trans()
- X{
- X bioslog("set trans to 0x%04x\n\r",BC);
- X HL=BC;
- X}
- X
- Xsel_dsk()
- X{
- X if (disks[BC&0xf]==NULL)
- X {
- X HL=0;
- X bioslog("Invalid disk select 0x%04x\n\r",BC);
- X }
- X else
- X {
- X HL=diskbufs[BC&0xf];
- X dsk=BC&0xf;
- X bioslog("Valid disk select [%x] 0x%4x\n\r",BC&0xf,HL);
- X }
- X}
- X
- Xset_trk()
- X{
- X bioslog("set track to 0x%02x\n\r",BC&0xff);
- X trk=BC&0xff;
- X}
- X
- Xset_sec()
- X{
- X bioslog("set sec to 0x%02x\n\r",BC&0xff);
- X sec=BC&0xff;
- X}
- X
- Xset_dma()
- X{
- X bioslog("set dma to 0x%04x\n\r",BC);
- X dma=BC;
- X}
- X
- Xread_dsk()
- X{
- X bioslog("Reading: track %d, sec %d, offset %d, dma 0x%4x\n\r",
- X trk, sec, 128*((trk*0x40)+sec), dma);
- X fseek(disks[dsk],128*((trk*0x40)+sec),0);
- X AF=(AF&0xff)|((fread(real_z80_mem+dma,128,1,disks[dsk])!=1)<<8);
- X}
- X
- Xwrite_dsk()
- X{
- X bioslog("Writing: track %d, sec %d, offset %d, dma 0x%4x\n\r",
- X trk, sec, 128*((trk*0x40)+sec), dma);
- X fseek(disks[dsk],128*((trk*0x40)+sec),0);
- X AF=(AF&0xff)|((fwrite(real_z80_mem+dma,128,1,disks[dsk])!=1)<<8);
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 bios.c &&
- chmod 0644 bios.c ||
- echo "restore of bios.c failed"
- set `wc -c bios.c`;Wc_c=$1
- if test "$Wc_c" != "5553"; then
- echo original size 5553, current size $Wc_c
- fi
- # ============= debug.c ==============
- echo "x - extracting debug.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > debug.c &&
- X/*
- X
- Xdebug.c - debugger for z-80 emulator.
- X
- X*/
- X
- X#include <stdio.h>
- X#include <setjmp.h>
- X#include <signal.h>
- X
- X#include "z80.h"
- Xextern char *sys_errlist[];
- Xextern int errno;
- X
- Xjmp_buf lj;
- X
- Xvoid int_handler()
- X{
- X longjmp(lj);
- X}
- X
- Xlong z80_memlines[65536];
- Xlong z80_memseeks[65536];
- XFILE *z80_file;
- X
- X
- X
- Xmain()
- X{
- X int i;
- X
- X setjmp(lj);
- X signal(SIGINT,int_handler);
- X
- X z80_file = 0;
- X while(1)
- X {
- X char ibuf[128], *istat;
- X
- X char cmd_char;
- X
- X do {
- X printf("\n>");
- X bzero(ibuf,127);
- X istat = fgets(ibuf, 127, stdin);
- X } while (istat && strlen(ibuf)<2);
- X if(!istat) break;
- X
- X cmd_char = ibuf[0];
- X switch(cmd_char)
- X {
- X case 'd':dump(ibuf);
- X break;
- X case 's':z80_instr(ibuf);
- X break;
- X case 'g':z80_run(ibuf);
- X break;
- X case 'c':pr_reg(ibuf);
- X break;
- X case 'l':gethex(ibuf);
- X break;
- X case 'b':getbin(ibuf);
- X break;
- X case 'm':movemem(ibuf);
- X break;
- X case 'w':writehex(ibuf);
- X break;
- X case 'y':getlines(ibuf);
- X break;
- X case 'r':set_reg(ibuf);
- X break;
- X case 'q':exit(0);
- X break;
- X case 'e':edit(ibuf);
- X break;
- X case '$':user_cmd(ibuf);
- X break;
- X default:help(ibuf);
- X break;
- X }
- X }
- X
- X}
- X
- X/*
- X
- Xon-line help
- X
- X*/
- X
- Xhelp(ibuf) char* ibuf;
- X{
- X printf("\nb file - load a binary image\n");
- X printf("c - display register values\n");
- X printf("d start [len] - display memory\n");
- X printf("e start - edit memory\n");
- X printf("g - start Z-80 running\n");
- X printf("l file - load hex file\n");
- X printf("m start end dest - move a chunk of memory\n");
- X printf("q - quit\n");
- X printf("r reg val - change register/flag value\n");
- X printf("s - single step\n");
- X printf("w start end file - write hex file\n");
- X printf("y file - read lines file\n");
- X printf("$ - execute user command\n");
- X}
- X
- X/*
- X
- Xdump
- X
- X*/
- X
- Xdump(ibuf) char* ibuf;
- X{
- X int start,end=0;
- X
- X if(2!=sscanf(ibuf,"%*s %x %x",&start,&end)) {
- X printf("usage: dump start end\n");
- X return;
- X }
- X pr_mem(start,end);
- X}
- X
- X/*
- X
- Xedit
- X
- X*/
- X
- Xedit(ibuf) char* ibuf;
- X{
- X int start,byte;
- X if(2!=sscanf(ibuf,"%*s %x %x",&start,&byte)) {
- X printf("usage: edit address value\n");
- X return;
- X }
- X start&=0xffff;
- X byte&=0xff;
- X real_z80_mem[start]=byte;
- X}
- X
- X/*
- X
- Xset registers
- X
- X*/
- X
- Xset_reg(ibuf) char* ibuf;
- X{
- X char reg[80];
- X int i;
- X if(2!=sscanf(ibuf,"%*s %s %x",reg, &i)) {
- X printf("usage: set register value\n");
- X return;
- X }
- X i&=0xffff;
- X if (!strcmp(reg,"pc"))
- X PC=i;
- X else if (!strcmp(reg,"sp"))
- X SP=i;
- X else if (!strcmp(reg,"af"))
- X AF=i;
- X else if (!strcmp(reg,"bc"))
- X BC=i;
- X else if (!strcmp(reg,"de"))
- X DE=i;
- X else if (!strcmp(reg,"hl"))
- X HL=i;
- X else if (!strcmp(reg,"af'"))
- X AF2=i;
- X else if (!strcmp(reg,"bc'"))
- X BC2=i;
- X else if (!strcmp(reg,"de'"))
- X DE2=i;
- X else if (!strcmp(reg,"hl'"))
- X HL2=i;
- X else if (!strcmp(reg,"ix"))
- X IX=i;
- X else if (!strcmp(reg,"iy"))
- X IY=i;
- X else if (!strcmp(reg,"i"))
- X IR=(IR&0xff)|(i<<8);
- X else if (!strcmp(reg,"r"))
- X IR=(IR&0xff00)|i;
- X else {
- X printf("register should be one of: pc sp af bc de hl af' bc' de' hl' ix iy i r\n");
- X }
- X}
- X
- X/*
- X
- Xdump out memory for the user. A is the starting address. L is the amount
- Xof dumping he wants. if L is 0, a default value is supplied.
- X
- X*/
- X
- Xpr_mem(a,l)
- XWORD a,l;
- X{
- X WORD i;
- X int counter=0;
- X
- X if (!l)
- X l=0x100;
- X for(i=0;i<l;i++)
- X {
- X if (!(counter%16))
- X printf("%04X- ",(a+i)&0xffff);
- X
- X printf("%02X ",real_z80_mem[(a+i)&0xffff]);
- X counter++;
- X
- X if (!(counter%16))
- X {
- X char c,j;
- X for (j=15;j>=0;j--)
- X {
- X c=real_z80_mem[(a+i-j)&0xffff]&0x7f;
- X putchar( ((c>0x20) && (c<0x7f))?c:'.' );
- X }
- X printf("\n");
- X }
- X }
- X if (counter%16)
- X {
- X int j;
- X char c;
- X for(j=counter%16;j>0;j--)
- X {
- X c=real_z80_mem[(a+i-j)&0xffff]&0x7f;
- X putchar( ((c>0x20) && (c<0x7f))?c:'.' );
- X }
- X printf("\n");
- X }
- X}
- X
- Xshow_debug_line(addr) WORD addr;
- X{
- X char ibuf[1024];
- X int ilow = addr, ihi = addr;
- X if(z80_file) {
- X while(ilow>0 && !z80_memlines[ilow]) ilow--;
- X while(ihi<65536 && !z80_memlines[ilow]) ihi++;
- X printf("(range %d %d)\n",ilow,ihi);
- X fseek(z80_file,z80_memseeks[ilow],0);
- X fgets(ibuf,1023,z80_file);
- X printf("%d: %s",z80_memlines[ilow],ibuf); /* \n included in ibuf... */
- X }
- X}
- X
- Xpr_reg(ibuf) char* ibuf;
- X{
- X static char *flag_chars="CNVxHxZS";
- X int i;
- X
- X printf("\nA =%02XH BC =%04XH DE =%04XH HL =%04XH SP=%04XH IX=%04XH\n"
- X ,AF>>8,BC,DE,HL,SP,IX);
- X printf("A'=%02XH BC'=%04XH DE'=%04XH HL'=%04XH PC=%04XH IY=%04XH\n"
- X ,AF2>>8,BC2,DE2,HL2,PC,IY);
- X
- X printf("\nI=%02XH R=%02XH F=",IR>>8,IR%0xff);
- X for(i=7;i>=0;i--)
- X putchar( (AF&(1<<i))?flag_chars[i]:'-' );
- X printf(" F'=");
- X for(i=7;i>=0;i--)
- X putchar( (AF2&(1<<i))?flag_chars[i]:'-' );
- X printf(" IFF1=%c IFF2=%c"
- X ,(INT_FLAGS&IFF1)?'1':'-',(INT_FLAGS&IFF2)?'1':'-');
- X
- X printf("\n(PC)=");
- X for(i=PC; i<PC+16; i++) {
- X printf("%02X ",real_z80_mem[i]);
- X }
- X printf("\n(HL)=");
- X for(i=HL; i<HL+16; i++) {
- X printf("%02X ",real_z80_mem[i]);
- X }
- X printf("\n");
- X
- X show_debug_line(PC);
- X}
- X
- Xgetlines(ibuf) char* ibuf;
- X{
- X char fname[80];
- X char lbuf[1024], *lstat;
- X
- X if(z80_file) {
- X int i;
- X fclose(z80_file);
- X for(i = 0; i<65536; i++) {
- X z80_memlines[i] = 0;
- X z80_memseeks[i] = 0;
- X }
- X }
- X sscanf(ibuf,"%*s %s",fname);
- X
- X z80_file=fopen(fname,"r");
- X if (z80_file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X /* long z80_memlines[65536]; */
- X do {
- X int addr, line, told;
- X told = ftell(z80_file);
- X lstat = fgets(lbuf, 1023, z80_file);
- X if(!lstat) break;
- X sscanf(lbuf,"%d: %x",&line,&addr);
- X z80_memlines[addr] = line;
- X z80_memseeks[addr] = told;
- X } while(lstat);
- X
- X /* fclose(file); */
- X}
- X
- X
- Xgethex(ibuf) char* ibuf;
- X{
- X char fname[80];
- X FILE *file;
- X
- X sscanf(ibuf,"%*s %s",fname);
- X
- X file=fopen(fname,"r");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X loadhex(file);
- X fclose(file);
- X}
- X
- Xgetbin(ibuf) char* ibuf;
- X{
- X char fname[80];
- X FILE *file;
- X WORD count=0;
- X
- X sscanf(ibuf,"%*s %s",fname);
- X
- X file=fopen(fname,"r");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X while (!feof(file))
- X real_z80_mem[count++]=getc(file);
- X fclose(file);
- X}
- X
- Xextern BYTE csum();
- X/*
- X#define HEXCHAR(a) ( ((a)>=10) ? ((a)+'a'-10) : ((a)+'0') )
- X*/
- Xchar HEXCHAR(a)
- Xchar a;
- X{
- X return ( ((a)>=10) ? ((a)+'a'-10) : ((a)+'0') );
- X}
- Xwritehex(ibuf) char* ibuf;
- X{
- X char fname[80],c[80];
- X FILE *file;
- X WORD start,end,i,j;
- X BYTE tmp;
- X char counter=0;
- X
- X if(3!=sscanf(ibuf,"%*s %hx %hx %s",&start,&end,fname)) {
- X printf("usage: write start end filename\n");
- X return;
- X }
- X end++;
- X
- X file=fopen(fname,"a");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X for(i=start;i<=end-32;i+=32)
- X {
- X strcpy(c,":20");
- X c[3]=HEXCHAR(i>>12);
- X c[4]=HEXCHAR((i>>8)&15);
- X c[5]=HEXCHAR((i>>4)&15);
- X c[6]=HEXCHAR(i&15);
- X c[7]='0';
- X c[8]='0';
- X for(j=0;j<32;j++)
- X {
- X c[ 9+2*j]=HEXCHAR(real_z80_mem[i+j]>>4);
- X c[10+2*j]=HEXCHAR(real_z80_mem[i+j]&15);
- X }
- X c[73]=0;
- X tmp=256-csum(c+1);
- X c[73]=HEXCHAR(tmp>>4);
- X c[74]=HEXCHAR(tmp&15);
- X c[75]=0;
- X fprintf(file,"%s\n",c);
- X }
- X if (i<end)
- X {
- X c[0]=':';
- X c[1]=HEXCHAR((end-i)>>4);
- X c[2]=HEXCHAR((end-i)&15);
- X c[3]=HEXCHAR(i>>12);
- X c[4]=HEXCHAR((i>>8)&15);
- X c[5]=HEXCHAR((i>>4)&15);
- X c[6]=HEXCHAR(i&15);
- X c[7]='0';
- X c[8]='0';
- X for (j=0;j<end-i;j++)
- X {
- X c[ 9+2*j]=HEXCHAR(real_z80_mem[i+j]>>4);
- X c[10+2*j]=HEXCHAR(real_z80_mem[i+j]&15);
- X }
- X c[ 9+2*(end-i)]=0;
- X tmp=256-csum(c+1);
- X c[ 9+2*(end-i)]=HEXCHAR(tmp>>4);
- X c[10+2*(end-i)]=HEXCHAR(tmp&15);
- X c[11+2*(end-i)]=0;
- X fprintf(file,"%s\n",c);
- X }
- X fprintf(file,":0000000000\n");
- X fclose(file);
- X}
- X
- Xmovemem(ibuf) char* ibuf;
- X{
- X WORD start,end,new,i;
- X
- X if(3!=sscanf(ibuf,"%*s %hx %hx %hx",&start,&end,&new)) {
- X printf("usage: move old_start old_end new_start\n");
- X return;
- X }
- X
- X for(i=start;i<=end;i++)
- X real_z80_mem[new+(i-start)]=real_z80_mem[i];
- X}
- X
- Xuser_cmd(ibuf) char* ibuf; /* for us, a relocator */
- X{
- X WORD start,end,bitmap,offset,i;
- X
- X if(4!=sscanf(ibuf,"%*s %hx %hx %hx %hx",&start,&end,&bitmap,&offset)) {
- X printf("usage: user_cmd start end bitmap offset\n");
- X return;
- X }
- X offset&=0xff;
- X
- X for (i=start;i<=end;i++)
- X if ( real_z80_mem[bitmap+((i-start)/8)] & (1<<((i-start)%8)) )
- X real_z80_mem[i]+=offset;
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 debug.c &&
- chmod 0644 debug.c ||
- echo "restore of debug.c failed"
- set `wc -c debug.c`;Wc_c=$1
- if test "$Wc_c" != "8597"; then
- echo original size 8597, current size $Wc_c
- fi
- # ============= io_ask.c ==============
- echo "x - extracting io_ask.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > io_ask.c &&
- X/*
- X
- Xio_ask.c - interactive I/O for Z-80 emulator.
- X
- X*/
- X
- X#include "z80.h"
- X#include <stdio.h>
- X
- XBYTE rdport(addr)
- XBYTE addr;
- X{
- X short data;
- X
- X printf("Z-80 reading from port %02XH:",addr);
- X scanf("%hx",&data);
- X return (BYTE) data;
- X}
- X
- Xwrport(addr,data)
- XBYTE addr,data;
- X{
- X printf("Z-80 writes %02XH to port %02XH\n",data,addr);
- X}
- X
- XBYTE int_read()
- X{
- X short data;
- X
- X printf("Z-80 reading for interrupt acknowledge:");
- X scanf("%hx",&data);
- X return (BYTE) data;
- X}
- X
- SHAR_EOF
- $TOUCH -am 0928182090 io_ask.c &&
- chmod 0644 io_ask.c ||
- echo "restore of io_ask.c failed"
- set `wc -c io_ask.c`;Wc_c=$1
- if test "$Wc_c" != "462"; then
- echo original size 462, current size $Wc_c
- fi
- # ============= io_mem.c ==============
- echo "x - extracting io_mem.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > io_mem.c &&
- X/*
- X
- Xio_mem.c: Implement a 256 byte RAM on the Z-80 I/O space.
- X
- X*/
- X
- X#include "z80.h"
- X
- XBYTE z80_io[256];
- X
- XBYTE rdport(addr)
- XBYTE addr;
- X{
- X return z80_io[addr];
- X}
- X
- Xwrport(addr,data)
- XBYTE addr,data;
- X{
- X z80_io[addr]=data;
- X}
- X
- XBYTE int_read()
- X{
- X return 255;
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 io_mem.c &&
- chmod 0644 io_mem.c ||
- echo "restore of io_mem.c failed"
- set `wc -c io_mem.c`;Wc_c=$1
- if test "$Wc_c" != "255"; then
- echo original size 255, current size $Wc_c
- fi
- # ============= lh.c ==============
- echo "x - extracting lh.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > lh.c &&
- X/*
- X
- XLoad .HEX format file into Z-80 memory.
- X
- X*/
- X
- X/* #include <stdio.h> */
- X#define NULL 0
- X#include <strings.h>
- X#include <ctype.h>
- X#include "z80.h"
- X
- XBYTE hexval(),hex_byte(),csum();
- X
- XBYTE hexval(c)
- Xchar c;
- X{
- X char *l;
- X static char digits[]="0123456789ABCDEF";
- X
- X if (islower(c))
- X c=toupper(c);
- X l=index(digits,c);
- X if (l==NULL)
- X return 255;
- X return l-digits;
- X}
- X
- SHAR_EOF
- $TOUCH -am 0928182090 lh.c &&
- chmod 0644 lh.c ||
- echo "restore of lh.c failed"
- set `wc -c lh.c`;Wc_c=$1
- if test "$Wc_c" != "373"; then
- echo original size 373, current size $Wc_c
- fi
- # ============= loadhex.c ==============
- echo "x - extracting loadhex.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > loadhex.c &&
- X/*
- X
- XLoad .HEX format file into Z-80 memory.
- X
- X*/
- X
- X#include <stdio.h>
- X#include <strings.h>
- X#include <ctype.h>
- X#include "z80.h"
- X
- XBYTE hexval(),hex_byte(),csum();
- X
- Xint getline(f,l)
- XFILE *f;
- Xchar *l;
- X{
- X int c;
- X
- X while((c=getc(f))!=EOF && c!='\n')
- X *l++=c;
- X if (c==EOF)
- X return 1;
- X *l=0;
- X return 0;
- X}
- X
- Xloadhex(f)
- XFILE *f;
- X{
- X char line[80],*ptr;
- X BYTE count,parse,i,cs;
- X WORD addr;
- X
- X while(!getline(f,line))
- X {
- X ptr=line;
- X if (index(ptr,':')==NULL)
- X continue;
- X ptr=index(ptr,':')+1;
- X if (cs=csum(ptr))
- X {
- X printf("Checksum error: %s\n",ptr);
- X continue;
- X }
- X count=hex_byte(ptr);
- X ptr+= 2;
- X addr=(hex_byte(ptr)<<8)|hex_byte(ptr+2);
- X ptr+= 4;
- X parse=hex_byte(ptr);
- X ptr+= 2;
- X
- X /* check parse byte if you want... */
- X
- X for(i=0;i<count;i++,ptr+= 2)
- X {
- X real_z80_mem[addr+i]=hex_byte(ptr);
- X }
- X }
- X
- X}
- X
- XBYTE hex_byte(c)
- Xchar *c;
- X{
- X return ((hexval(*c)<<4)|hexval(*(c+1)));
- X}
- X
- XBYTE hexval(c)
- Xchar c;
- X{
- X char *l;
- X static char digits[]="0123456789ABCDEF";
- X
- X if (islower(c))
- X c=toupper(c);
- X l=index(digits,c);
- X if (l==NULL)
- X return 255;
- X return l-digits;
- X}
- X
- XBYTE csum(l)
- Xchar *l;
- X{
- X BYTE csum=0;
- X
- X while(strlen(l))
- X {
- X csum+=(hex_byte(l)&0xff);
- X l+=2;
- X }
- X
- X return csum;
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 loadhex.c &&
- chmod 0644 loadhex.c ||
- echo "restore of loadhex.c failed"
- set `wc -c loadhex.c`;Wc_c=$1
- if test "$Wc_c" != "1262"; then
- echo original size 1262, current size $Wc_c
- fi
- # ============= makedrive.c ==============
- echo "x - extracting makedrive.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > makedrive.c &&
- X/*
- X
- Xmakedrive.c - creates a "drive device" file for CP/M - really a file
- Xwith a size a multiple of 2K and more than 128K, with the first 16K
- Xfilled with $E5, and a hole for the rest up to the EOF. This creates
- Xa file that takes up 16K on disk, but has a huge EOF. Under CP/M, the
- XEOF of a "drive device" file defines its size, which (of course)
- Xdoesn't change.
- X
- X*/
- X
- X#include <stdio.h>
- X
- Xextern int errno;
- Xextern char *sys_errlist[];
- X
- Xusage(name)
- Xchar *name;
- X{
- X printf("Usage: %s [size] [filename]\n\n",name);
- X printf("size is in K-bytes and must be an even number 128 or greater.\n\n");
- X exit(1);
- X}
- X
- Xmain(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X int size,i;
- X FILE *f;
- X
- X if (argc!=3)
- X usage(*argv);
- X
- X size=atoi(argv[1]);
- X
- X if (size<128 || size%2)
- X usage(*argv);
- X
- X f=fopen(argv[2],"w");
- X if (f==NULL)
- X {
- X printf("%s: %s - %s\n",*argv,argv[2],sys_errlist[errno]);
- X exit(1);
- X }
- X
- X for (i=0;i<16384*4;i++) /* write out a blank directory */
- X putc(0xE5,f);
- X
- X fseek(f,(long)(1024*size-1),0); /* make a big hole */
- X putc(0xE5,f);
- X
- X fclose(f);
- X
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 makedrive.c &&
- chmod 0644 makedrive.c ||
- echo "restore of makedrive.c failed"
- set `wc -c makedrive.c`;Wc_c=$1
- if test "$Wc_c" != "1062"; then
- echo original size 1062, current size $Wc_c
- fi
- # ============= udbg.c ==============
- echo "x - extracting udbg.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > udbg.c &&
- X/*
- X
- Xdebug.c - debugger for z-80 emulator.
- X
- X*/
- X
- X#include <stdio.h>
- X#include <setjmp.h>
- X#include <signal.h>
- X
- X#include "z80.h"
- Xextern char *sys_errlist[];
- Xextern int errno;
- X
- Xjmp_buf lj;
- X
- Xvoid int_handler()
- X{
- X longjmp(lj);
- X}
- X
- Xlong z80_memlines[65536];
- Xlong z80_memseeks[65536];
- XFILE *z80_file;
- X
- X
- X#include <sgtty.h>
- Xextern struct sgttyb tty_sgtty_data;
- X
- X
- Xdebug_write(x,y)
- X WORD x;
- X BYTE y;
- X{
- X if(x==TWRTval) { /* bdos storage of user # == 0xedfe*/
- X printf("\n\r0x%04x:%02x\n\r",x,y);
- X debugit();
- X }
- X real_z80_mem[x]=y;
- X}
- X
- X
- Xdebugit()
- X{
- X int i;
- X
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags&=~RAW;
- X tty_sgtty_data.sg_flags|=ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X
- X z80_file = 0;
- X while(1)
- X {
- X char ibuf[128], *istat;
- X
- X char cmd_char;
- X
- X do {
- X printf("\n>");
- X bzero(ibuf,127);
- X istat = fgets(ibuf, 127, stdin);
- X } while (istat && strlen(ibuf)<2);
- X if(!istat) break;
- X
- X cmd_char = ibuf[0];
- X switch(cmd_char)
- X {
- X case 'd':dump(ibuf);
- X break;
- X case 'G':/* z80_run(ibuf) */
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags|=RAW;
- X tty_sgtty_data.sg_flags&=~ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X return 1;
- X case 'g':/* z80_run(ibuf) */
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags|=RAW;
- X tty_sgtty_data.sg_flags&=~ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X return 0;
- X break;
- X case 's':z80_instr(ibuf);
- X /* break; */ /* really fall through */
- X case 'c':pr_reg(ibuf);
- X break;
- X case 'l':gethex(ibuf);
- X break;
- X case 'b':getbin(ibuf);
- X break;
- X case 'm':movemem(ibuf);
- X break;
- X case 'w':writehex(ibuf);
- X break;
- X case 'y':getlines(ibuf);
- X break;
- X case 'r':set_reg(ibuf);
- X break;
- X case 'q':
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags|=RAW;
- X tty_sgtty_data.sg_flags&=~ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X exit(0);
- X break;
- X case 'e':edit(ibuf);
- X break;
- X case '$':user_cmd(ibuf);
- X break;
- X default:help(ibuf);
- X break;
- X }
- X }
- X
- X}
- X
- X/*
- X
- Xon-line help
- X
- X*/
- X
- Xhelp(ibuf) char* ibuf;
- X{
- X printf("\nb file - load a binary image\n");
- X printf("c - display register values\n");
- X printf("d start [len] - display memory\n");
- X printf("e start - edit memory\n");
- X printf("g - start Z-80 running\n");
- X printf("l file - load hex file\n");
- X printf("m start end dest - move a chunk of memory\n");
- X printf("q - quit\n");
- X printf("r reg val - change register/flag value\n");
- X printf("s - single step\n");
- X printf("w start end file - write hex file\n");
- X printf("y file - read lines file\n");
- X printf("$ - execute user command\n");
- X}
- X
- X/*
- X
- Xdump
- X
- X*/
- X
- Xdump(ibuf) char* ibuf;
- X{
- X int start,end=0;
- X
- X if(2!=sscanf(ibuf,"%*s %x %x",&start,&end)) {
- X printf("usage: dump start end\n");
- X return;
- X }
- X pr_mem(start,end);
- X}
- X
- X/*
- X
- Xedit
- X
- X*/
- X
- Xedit(ibuf) char* ibuf;
- X{
- X int start,byte;
- X if(2!=sscanf(ibuf,"%*s %x %x",&start,&byte)) {
- X printf("usage: edit address value\n");
- X return;
- X }
- X start&=0xffff;
- X byte&=0xff;
- X real_z80_mem[start]=byte;
- X}
- X
- X/*
- X
- Xset registers
- X
- X*/
- X
- Xset_reg(ibuf) char* ibuf;
- X{
- X char reg[80];
- X int i;
- X if(2!=sscanf(ibuf,"%*s %s %x",reg, &i)) {
- X printf("usage: set register value\n");
- X return;
- X }
- X i&=0xffff;
- X if (!strcmp(reg,"pc"))
- X PC=i;
- X else if (!strcmp(reg,"sp"))
- X SP=i;
- X else if (!strcmp(reg,"af"))
- X AF=i;
- X else if (!strcmp(reg,"bc"))
- X BC=i;
- X else if (!strcmp(reg,"de"))
- X DE=i;
- X else if (!strcmp(reg,"hl"))
- X HL=i;
- X else if (!strcmp(reg,"af'"))
- X AF2=i;
- X else if (!strcmp(reg,"bc'"))
- X BC2=i;
- X else if (!strcmp(reg,"de'"))
- X DE2=i;
- X else if (!strcmp(reg,"hl'"))
- X HL2=i;
- X else if (!strcmp(reg,"ix"))
- X IX=i;
- X else if (!strcmp(reg,"iy"))
- X IY=i;
- X else if (!strcmp(reg,"i"))
- X IR=(IR&0xff)|(i<<8);
- X else if (!strcmp(reg,"r"))
- X IR=(IR&0xff00)|i;
- X else {
- X printf("register should be one of: pc sp af bc de hl af' bc' de' hl' ix iy i r\n");
- X }
- X}
- X
- X/*
- X
- Xdump out memory for the user. A is the starting address. L is the amount
- Xof dumping he wants. if L is 0, a default value is supplied.
- X
- X*/
- X
- Xpr_mem(a,l)
- XWORD a,l;
- X{
- X WORD i;
- X int counter=0;
- X
- X if (!l)
- X l=0x100;
- X for(i=0;i<l;i++)
- X {
- X if (!(counter%16))
- X printf("%04X- ",(a+i)&0xffff);
- X
- X printf("%02X ",real_z80_mem[(a+i)&0xffff]);
- X counter++;
- X
- X if (!(counter%16))
- X {
- X char c; int j;
- X for (j=15;j>=0;j--)
- X {
- X c=real_z80_mem[(a+i-j)&0xffff]&0x7f;
- X putchar( ((c>0x20) && (c<0x7f))?c:'.' );
- X }
- X printf("\n");
- X }
- X }
- X if (counter%16)
- X {
- X int j;
- X char c;
- X for(j=counter%16;j>0;j--)
- X {
- X c=real_z80_mem[(a+i-j)&0xffff]&0x7f;
- X putchar( ((c>0x20) && (c<0x7f))?c:'.' );
- X }
- X printf("\n");
- X }
- X}
- X
- Xshow_debug_line(addr) WORD addr;
- X{
- X char ibuf[1024];
- X int ilow = addr, ihi = addr;
- X if(z80_file) {
- X while(ilow>0 && !z80_memlines[ilow]) ilow--;
- X while(ihi<65536 && !z80_memlines[ilow]) ihi++;
- X printf("(range %d %d)\n",ilow,ihi);
- X fseek(z80_file,z80_memseeks[ilow],0);
- X fgets(ibuf,1023,z80_file);
- X printf("%d: %s",z80_memlines[ilow],ibuf); /* \n included in ibuf... */
- X }
- X}
- X
- Xpr_reg(ibuf) char* ibuf;
- X{
- X static char *flag_chars="CNVxHxZS";
- X int i;
- X
- X printf("\nA =%02XH BC =%04XH DE =%04XH HL =%04XH SP=%04XH IX=%04XH\n"
- X ,AF>>8,BC,DE,HL,SP,IX);
- X printf("A'=%02XH BC'=%04XH DE'=%04XH HL'=%04XH PC=%04XH IY=%04XH\n"
- X ,AF2>>8,BC2,DE2,HL2,PC,IY);
- X
- X printf("\nI=%02XH R=%02XH F=",IR>>8,IR%0xff);
- X for(i=7;i>=0;i--)
- X putchar( (AF&(1<<i))?flag_chars[i]:'-' );
- X printf(" F'=");
- X for(i=7;i>=0;i--)
- X putchar( (AF2&(1<<i))?flag_chars[i]:'-' );
- X printf(" IFF1=%c IFF2=%c"
- X ,(INT_FLAGS&IFF1)?'1':'-',(INT_FLAGS&IFF2)?'1':'-');
- X
- X printf("\n(PC)=");
- X for(i=PC; i<PC+16; i++) {
- X printf("%02X ",real_z80_mem[i]);
- X }
- X printf("\n(HL)=");
- X for(i=HL; i<HL+16; i++) {
- X printf("%02X ",real_z80_mem[i]);
- X }
- X printf("\n(SP)=");
- X for(i=SP; i<SP+16; i++) {
- X printf("%02X ",real_z80_mem[i]);
- X }
- X printf("\n");
- X
- X show_debug_line(PC);
- X}
- X
- Xgetlines(ibuf) char* ibuf;
- X{
- X char fname[80];
- X char lbuf[1024], *lstat;
- X
- X if(z80_file) {
- X int i;
- X fclose(z80_file);
- X for(i = 0; i<65536; i++) {
- X z80_memlines[i] = 0;
- X z80_memseeks[i] = 0;
- X }
- X }
- X sscanf(ibuf,"%*s %s",fname);
- X
- X z80_file=fopen(fname,"r");
- X if (z80_file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X /* long z80_memlines[65536]; */
- X do {
- X int addr, line, told;
- X told = ftell(z80_file);
- X lstat = fgets(lbuf, 1023, z80_file);
- X if(!lstat) break;
- X sscanf(lbuf,"%d: %x",&line,&addr);
- X z80_memlines[addr] = line;
- X z80_memseeks[addr] = told;
- X } while(lstat);
- X
- X /* fclose(file); */
- X}
- X
- X
- Xgethex(ibuf) char* ibuf;
- X{
- X char fname[80];
- X FILE *file;
- X
- X sscanf(ibuf,"%*s %s",fname);
- X
- X file=fopen(fname,"r");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X loadhex(file);
- X fclose(file);
- X}
- X
- Xgetbin(ibuf) char* ibuf;
- X{
- X char fname[80];
- X FILE *file;
- X WORD icount=0,count=0;
- X
- X if(2!=sscanf(ibuf,"%*s %hx %s",&icount,fname)) {
- X printf("usage: getbin offset filename\n");
- X return;
- X };
- X
- X file=fopen(fname,"r");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X count=icount;
- X printf("loading %s into %04x\n",fname,count);
- X while (!feof(file))
- X real_z80_mem[count++]=getc(file);
- X fclose(file);
- X printf("loaded %d bytes (save %d foo.com)\n",count-icount,((count-icount)/256)+1);
- X}
- X
- Xextern BYTE csum();
- X/*
- X#define HEXCHAR(a) ( ((a)>=10) ? ((a)+'a'-10) : ((a)+'0') )
- X*/
- Xchar HEXCHAR(a)
- Xchar a;
- X{
- X return ( ((a)>=10) ? ((a)+'a'-10) : ((a)+'0') );
- X}
- Xwritehex(ibuf) char* ibuf;
- X{
- X char fname[80],c[80];
- X FILE *file;
- X WORD start,end,i,j;
- X BYTE tmp;
- X char counter=0;
- X
- X if(3!=sscanf(ibuf,"%*s %hx %hx %s",&start,&end,fname)) {
- X printf("usage: write start end filename\n");
- X return;
- X }
- X end++;
- X
- X file=fopen(fname,"a");
- X if (file==NULL)
- X {
- X printf("%s: %s",fname,sys_errlist[errno]);
- X return;
- X }
- X for(i=start;i<=end-32;i+=32)
- X {
- X strcpy(c,":20");
- X c[3]=HEXCHAR(i>>12);
- X c[4]=HEXCHAR((i>>8)&15);
- X c[5]=HEXCHAR((i>>4)&15);
- X c[6]=HEXCHAR(i&15);
- X c[7]='0';
- X c[8]='0';
- X for(j=0;j<32;j++)
- X {
- X c[ 9+2*j]=HEXCHAR(real_z80_mem[i+j]>>4);
- X c[10+2*j]=HEXCHAR(real_z80_mem[i+j]&15);
- X }
- X c[73]=0;
- X tmp=256-csum(c+1);
- X c[73]=HEXCHAR(tmp>>4);
- X c[74]=HEXCHAR(tmp&15);
- X c[75]=0;
- X fprintf(file,"%s\n",c);
- X }
- X if (i<end)
- X {
- X c[1]=HEXCHAR((end-i)>>4);
- X c[2]=HEXCHAR((end-i)&15);
- X c[3]=HEXCHAR(i>>12);
- X c[4]=HEXCHAR((i>>8)&15);
- X c[5]=HEXCHAR((i>>4)&15);
- X c[6]=HEXCHAR(i&15);
- X c[7]='0';
- X c[8]='0';
- X for (j=0;j<end-i;j++)
- X {
- X c[ 9+2*j]=HEXCHAR(real_z80_mem[i+j]>>4);
- X c[10+2*j]=HEXCHAR(real_z80_mem[i+j]&15);
- X }
- X c[ 9+2*(end-i)]=0;
- X tmp=256-csum(c+1);
- X c[ 9+2*(end-i)]=HEXCHAR(tmp>>4);
- X c[10+2*(end-i)]=HEXCHAR(tmp&15);
- X c[11+2*(end-i)]=0;
- X fprintf(file,"%s\n",c);
- X }
- X fprintf(file,":0000000000\n");
- X fclose(file);
- X}
- X
- Xmovemem(ibuf) char* ibuf;
- X{
- X WORD start,end,new,i;
- X
- X if(3!=sscanf(ibuf,"%*s %hx %hx %hx",&start,&end,&new)) {
- X printf("usage: move old_start old_end new_start\n");
- X return;
- X }
- X
- X for(i=start;i<=end;i++)
- X real_z80_mem[new+(i-start)]=real_z80_mem[i];
- X}
- X
- Xuser_cmd(ibuf) char* ibuf; /* for us, a relocator */
- X{
- X WORD start,end,bitmap,offset,i;
- X
- X if(4!=sscanf(ibuf,"%*s %hx %hx %hx %hx",&start,&end,&bitmap,&offset)) {
- X printf("usage: user_cmd start end bitmap offset\n");
- X return;
- X }
- X offset&=0xff;
- X
- X for (i=start;i<=end;i++)
- X if ( real_z80_mem[bitmap+((i-start)/8)] & (1<<((i-start)%8)) )
- X real_z80_mem[i]+=offset;
- X}
- SHAR_EOF
- $TOUCH -am 0928182090 udbg.c &&
- chmod 0644 udbg.c ||
- echo "restore of udbg.c failed"
- set `wc -c udbg.c`;Wc_c=$1
- if test "$Wc_c" != "9809"; then
- echo original size 9809, current size $Wc_c
- fi
- # ============= upm.c ==============
- echo "x - extracting upm.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > upm.c &&
- X/*
- X
- Xup/m - unix CP/M.
- X
- X(C) MCMXC - Nick Sayer - All rights reserved.
- X
- XSee COPYRIGHT file for more details.
- X
- X
- XConfiguration section.
- X
- X
- XCPM_FILE - default file with CP/M HEX images.
- X
- XAddresses 0-2K are CCP, 2K-5.5K - BDOS. 5.5K-16K - BIOS. Address 65535
- Xwill have the length (in pages) of CP/M.
- X
- XAddresses 16K-? - relocation bitmap. Each bit in the bitmap represents
- Xa BYTE in 0-16K. If the bit is 1, the high byte of the first address of
- Xthe destination address for the CCP should be added to the byte in 0-16K
- Ximage. That image is then moved to the proper location. The PC is set to
- X32K and the Z-80 starts running. The high byte of the first byte of the
- XCCP destination address is gotten from address 65535. This value is
- Xthen adjusted if CP/M is to be relocated lower than the default
- Xtop of memory. The CP/M image to load should have a resident run address
- Xbefore relocation of 0.
- X
- X*/
- X#define CPM_FILE "CPM"
- X
- X#include <strings.h>
- X#include <ctype.h>
- X#include <sgtty.h>
- X#include <signal.h>
- X
- X#include "upm.h"
- X
- XWORD topmem=256; /* These may be changed by arguments */
- Xchar *cpm_file=CPM_FILE;
- X
- Xstruct sgttyb tty_sgtty_data;
- X
- Xstatic BYTE dph[32]={
- X
- X/* Disk Paramater Header (diskbufs[]) */
- X
- X0x00,0x00, /* TRANSTABLE unused */
- X0x00,0x00, /* unused */
- X0x00,0x00,
- X0x00,0x00,
- X0x80,0xff, /* DIRBUF - patch with topmem-1 later */
- X0x10,0xff, /* DPB - patch with OUR page no. */
- X0x00,0x00, /* CHKVEC - not used */
- X0x20,0xff, /* ALLOCVEC - patch with OUR page no. */
- X
- X/* Disk Paramater Block */
- X
- X0x40,0x00, /* Sectors per track */
- X0x04, /* Block Shift */
- X0x0f, /* Block Mask */
- X0x00, /* Extent Mask */
- X0x00,0x10, /* Blocks on device - patch if variable size implemented */
- X0xff,0x01, /* Directory entries -1 */
- X0xff,0x00, /* Allocation masks for directory */
- X0x00,0x00, /* Check vector size - patch if checkvecs implemented */
- X0x00,0x00, /* offset to first user-track */
- X0x00 /* spare */
- X};
- X
- X/* These are externs in upm.h, but they have to be declared somewhere. */
- X
- XFILE *disks[16],*devices[5];
- XWORD diskbufs[16];
- XBYTE ccp_image[SIZE_CCP_IMAGE];
- XWORD ccp_start;
- X
- X/*
- X
- Xrelocade(address);
- XBYTE address;
- X
- XRelocate CP/M image at 0000-4000 using bitmap at 4000-4800.
- XCopy image to new location, and copy first 5.5K to ccp_image[];
- XStop if we get to the top of RAM.
- X
- X*/
- X
- Xrelocate(add,len)
- XBYTE add;
- X{
- X WORD i;
- X
- X for (i=0;i!=(256*len);i++)
- X {
- X if ( real_z80_mem[16384+(i>>3)]&(1<<(i&7)) )
- X real_z80_mem[i]=real_z80_mem[i]+add;
- X real_z80_mem[i+(add<<8)]=real_z80_mem[i];
- X if (i<SIZE_CCP_IMAGE)
- X ccp_image[i]=real_z80_mem[i];
- X }
- X}
- Xint debugflag = 0;
- Xint dlogflag = 0;
- X
- Xdebugit();
- X
- Xmain(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X FILE *cpm;
- X char line[80];
- X int i;
- X
- X signal(SIGINT,debugit);
- X
- X for(i=0;i<16;i++)
- X {
- X disks[i]=NULL;
- X devices[i%5]=NULL; /* hack: only do 0-4 */
- X }
- X
- X/* OPEN ~/.upmrc, send each line to process_args(line); */
- X
- X argc--; argv++;
- X for(;argc--;argv++)
- X process_args(*argv);
- X
- X if (disks[0]==NULL)
- X {
- X printf("A: must be assigned.\n");
- X exit(0);
- X }
- X
- X/*
- X
- XFor each non-null pointer in disks[], lower topmem, and save the pointer
- Xto diskbufs[]. This assigns space for the allocation vector, and the
- XDPH/DPB. Then copy in a "standard" DPH/DPB into the bottom. We'll
- Xpatch it later.
- X
- XWe really should allow disks to be sized at runtime, but for now
- Xthey're fixed at 8MB, so we lower topmem 3 for each one. 2 pages
- Xfor the alloc table, another page (actually 32 bytes)
- Xfor the miscelany.
- X
- X*/
- X
- X for(i=0;i!=16;i++)
- X {
- X char j;
- X
- X if (disks[i]==NULL)
- X continue;
- X topmem-=3;
- X diskbufs[i]=topmem<<8;
- X for(j=0;j!=32;j++)
- X real_z80_mem[diskbufs[i]+j]=dph[j];
- X real_z80_mem[diskbufs[i]+0x0b]=real_z80_mem[diskbufs[i]+0x0f]=topmem;
- X }
- X
- X/*
- X
- XNow for each non-null disk[] readjust the dirbuf pointer.
- XWe couldn't do it before because we didn't have a final
- Xlocation for dirbuf. topmem-1 is the high-byte of the
- Xfinal location for dirbuf. the low byte is 0x80.
- XThis page of memory is shared with the BIOS "jump" table.
- X
- X*/
- X
- X for(i=0;i!=16;i++)
- X {
- X if (disks[i]==NULL)
- X continue;
- X real_z80_mem[diskbufs[i]+9]=topmem-1;
- X }
- X
- X cpm=fopen(cpm_file,"r");
- X if (cpm==NULL)
- X {
- X printf("Can't open CP/M binaries: %s\n",sys_errlist[errno]);
- X exit(1);
- X }
- X loadhex(cpm);
- X
- X ccp_start=(topmem-real_z80_mem[65535])<<8;
- X relocate(topmem-real_z80_mem[65535],real_z80_mem[65535]);
- X
- X PC=0x8000;
- X
- X/*
- X
- XNow set up the terminal. Just toggling RAW should be enough.
- X
- X*/
- X
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags|=RAW;
- X tty_sgtty_data.sg_flags&=~ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X
- X do
- X { z80_run();
- X if(debugflag>1 && debugit()) PC++;
- X else if(bios()) break;
- X } while(1); /* } while(!bios()); */
- X
- X gtty(fileno(stdin),&tty_sgtty_data);
- X tty_sgtty_data.sg_flags&=~RAW;
- X tty_sgtty_data.sg_flags|=ECHO;
- X stty(fileno(stdin),&tty_sgtty_data);
- X}
- X
- X/*
- X
- XThe arguments can include A:file-O:file, {TY, LP, PT, U1, U2}:file,
- Xmem:0-128.
- X
- XDisk files are fopen()ed "r+", and are assigned to disks[].
- XDevice files are fopen()ed "r+" and are assigned to devices[], except
- Xfor LP:, which is fopen()ed "w".
- X
- XThe value after mem: lowers the top of memory by that many pages (256
- Xbytes) to save space for things like BYE, etc.
- X
- XThe arguments MUST be stripped of white-spaces.
- X
- X*/
- X
- Xprocess_args(arg)
- Xchar *arg;
- X{
- X char i,left[80],*right;
- X
- X if (index(arg,':')==NULL)
- X {
- X printf("Missing ':' in argument.\n");
- X return;
- X }
- X
- X strcpy(left,arg);
- X right=index(left,':')+1;
- X *index(left,':')='\0';
- X for(i=0;i!=strlen(left);i++)
- X if (islower(left[i]))
- X left[i]=toupper(left[i]);
- X
- X if (strlen(left)==1 && (*left<='O') && (*left>='A'))
- X {
- X disks[*left-'A']=fopen(right,"r+");
- X return;
- X }
- X if (!strcmp(left,"MEM"))
- X {
- X topmem-=atoi(right);
- X return;
- X }
- X if (!strcmp(left,"TY"))
- X {
- X devices[F_TY]=fopen(right,"r+");
- X return;
- X }
- X if (!strcmp(left,"PT"))
- X {
- X devices[F_PT]=fopen(right,"r+");
- X return;
- X }
- X if (!strcmp(left,"LP"))
- X {
- X devices[F_LP]=fopen(right,"w");
- X return;
- X }
- X if (!strcmp(left,"U1"))
- X {
- X devices[F_U1]=fopen(right,"r+");
- X return;
- X }
- X if (!strcmp(left,"U2"))
- X {
- X devices[F_U2]=fopen(right,"r+");
- X return;
- X }
- X if (!strcmp(left,"DEBUG"))
- X {
- X debugflag=atoi(right);
- X return;
- X }
- X if (!strcmp(left,"DLOG"))
- X {
- X dlogflag=atoi(right);
- X return;
- X }
- X if (!strcmp(left,"BIOS"))
- X {
- X biosflag=atoi(right);
- X return;
- X }
- X if (!strcmp(left,"TRAP"))
- X {
- X sscanf(right,"%4x",&TRAPval);
- X return;
- X }
- X if (!strcmp(left,"TWRT"))
- X {
- X sscanf(right,"%4x",&TWRTval);
- X return;
- X }
- X}
- X
- Xcoredump()
- X{
- X FILE *qb;
- X int i;
- X
- X qb=fopen("mem","w");
- X for(i=0;i!=65536;i++)
- X putc(real_z80_mem[i],qb);
- X fclose(qb);
- X}
- SHAR_EOF
- $TOUCH -am 0928214490 upm.c &&
- chmod 0644 upm.c ||
- echo "restore of upm.c failed"
- set `wc -c upm.c`;Wc_c=$1
- if test "$Wc_c" != "6850"; then
- echo original size 6850, current size $Wc_c
- fi
- # ============= upm.h ==============
- echo "x - extracting upm.h (Text)"
- sed 's/^X//' << 'SHAR_EOF' > upm.h &&
- X/*
- X
- Xupm.h - common data for upm.
- X
- X(C) MCMXC - Nick Sayer - All rights reserved.
- X
- X*/
- X
- X#include <stdio.h>
- X#include "z80.h"
- Xextern char *sys_errlist[];
- Xextern int errno;
- X
- Xextern FILE *disks[16],*devices[5]; /* These are FILEs for CP/M devices */
- X
- Xextern WORD diskbufs[16]; /* These are pointers to disk paramater
- X tables. See sel_dsk() */
- X
- X/* Which devices[] go to which physical devices? */
- X#define F_TTY 0
- X#define F_LPT 1
- X#define F_PTP 2
- X#define F_PTR 2
- X#define F_UL1 3
- X#define F_UC1 3
- X#define F_UP1 3
- X#define F_UR1 3
- X#define F_UR2 4
- X#define F_UP2 4
- X
- X/* Which command line args go to which physical devices? */
- X#define F_TY 0
- X#define F_LP 1
- X#define F_PT 2
- X#define F_U1 3
- X#define F_U2 4
- X
- X/*
- X
- XWhen CP/M is run on a real system, the warm boot procedure reads
- Xin the CCP image from disk. Of course, we don't have a real disk,
- Xso the startup procedure for the emulator places the relocated
- Ximage of the ccp into the following structure. Actually, the
- Ximage size is 5.5K, so it incorporates BDOS as well.
- X
- X*/
- X
- X#define SIZE_CCP_IMAGE 5632
- Xextern BYTE ccp_image[SIZE_CCP_IMAGE]; /* Save CCP for warm boot */
- Xextern WORD ccp_start; /* ... and where to put it */
- X
- X/*
- X
- Xbios() implements the CP/M bios in C. The BIOS function to execute is
- Xdetermined by ((PC&0xff)/3). This assumes the BIOS starts on an even
- Xpage boundary, which in most cases is a requirement anyway. This allows
- Xall sorts of silly things to happen if programs crunch up in strange
- Xways, but that happens a lot with CP/M anyway. This routine takes no
- Xformal arguments, and has all sorts of side effects on the Z-80
- Xregister pairs and the Z-80 memory space. The return value is non-zero
- Xif the EXIT BIOS entry (HALT at xx5D) is called.
- X
- X*/
- X
- Xextern char bios();
- SHAR_EOF
- $TOUCH -am 0928182090 upm.h &&
- chmod 0644 upm.h ||
- echo "restore of upm.h failed"
- set `wc -c upm.h`;Wc_c=$1
- if test "$Wc_c" != "1744"; then
- echo original size 1744, current size $Wc_c
- fi
- # ============= z80.c ==============
- echo "x - extracting z80.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > z80.c &&
- X/*
- X
- Xz80.c - Z-80 microprocessor emulator.
- X
- XCopyright MCMXC - Nick Sayer - All rights reserved.
- X
- XSee COPYRIGHT file for details.
- X
- Xv0.0 - 04/08/90 - epoch
- Xv0.0A0 - 04/13/90 - alpha-test.
- Xv0.0A1 - 08/04/90 - alpha-test 2.
- Xv0.0A2 - 09/04/90 - alpha-test 3.
- X
- Xglobal data types:
- X
- XWORD = unsigned short - i.e. an address or register pair.
- XBYTE = unsigned char - i.e. a memory location or register.
- X
- Xglobal data:
- X
- XBYTE z80_mem[65536];
- XWORD AF,BC,DE,HL,SP,PC,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
- X
- Xglobal routines:
- X
- Xz80_run();
- X
- X Start running at addr. PRESUMES PC AND OTHER REGISTERS SET PROPERLY!!!
- X Returns if Z-80 executes a HALT. Returns with PC set to address of HALT
- X instruction.
- X
- Xz80_instr();
- X
- X Execute a single instruction.
- X
- Xwrport(addr,data);
- XBYTE addr,data;
- X
- XBYTE rdport(addr);
- XBYTE addr;
- X
- X These routines are called by the Z-80 when it wants to read or write
- X to the port-space.
- X
- Xchar INT,NMI,RESET;
- X
- X Each of these starts at 0. If some event makes any of these true, the
- X event each represents will take place. Think of them as the coresponding
- X wires that go into the CPU, except that in the real CPU these wires are
- X inverse logic.
- X
- XBYTE int_read();
- X
- X This routine called on an interrupt. It should return the proper
- X interrupt acknowledgement cycle data.
- X
- XKNOWN "FEATURES":
- X
- X This actually simulates a MOSTEK MK 3880. Whether or not this
- X device differs from the Zilog product, I don't know. But I
- X doubt it.
- X
- X If you single-step using z80_instr(), memory refresh, interrupt
- X checking, and similar housekeeping will NOT take place.
- X
- X If the processor is in interrupt mode 0, the int_read()
- X value MUST be an RST instruction.
- X
- X Undefined opcode sequences WILL have truely bizarre and twisted
- X results. Count on it. Especially undefined DD/FD operations.
- X
- X "Interrupting devices" at this time can't tell when an interrupt
- X service routine is finished. Normally they monitor the bus
- X waiting for a RETI instruction. There's no way to do that with
- X this code yet.
- X
- X*/
- X
- X#include "z80.h"
- X
- XBYTE real_z80_mem[65536];
- Xchar STOP_FLAG; /* hack to stop us on HALT */
- Xchar INT=0,NMI=0,RESET=0;
- XWORD AF,BC,DE,HL,PC,SP,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
- Xint TRAPval = -1, lastPC = -1;
- X
- Xz80_run()
- X{
- X STOP_FLAG=0;
- X do
- X {
- X
- X/* do an instruction */
- X
- X if (PC == TRAPval) {
- X printf("\n\rTrapping at 0x%04x (last=0x%04x)\n\r",PC,lastPC);
- X debugit();
- X }
- X lastPC = PC;
- X z80_instr();
- X
- X/* If we did an EI instruction before last, set both IFFs */
- X
- X if (INT_FLAGS&IFTMP)
- X {
- X INT_FLAGS-=0x10;
- X if (!(INT_FLAGS&IFTMP))
- X INT_FLAGS|=IFF1|IFF2;
- X }
- X
- X/* If an interrupt is pending and they're enabled, do it */
- X
- X if (INT && INT_FLAGS&IFF1)
- X {
- X register WORD operand;
- X
- X INT_FLAGS&=~(IFF1|IFF2);
- X push(PC);
- X switch (INT_FLAGS&IM_STAT)
- X {
- X case 0:PC=int_read()&0x38; /* DANGEROUSLY assumes an RST op... */
- X break;
- X case 1:PC=0x38; int_read(); /* we have to fetch, then spike it */
- X break;
- X case 2:operand=(IR&0xff80)|(int_read()&0xfe);
- X PC=z80_mem(operand)|(z80_mem(operand+1)<<8);
- X break;
- X }
- X INT=0;
- X }
- X
- X/* If an NMI is pending, do it */
- X
- X if (NMI)
- X {
- X INT_FLAGS&=~IFF1;
- X push(PC);
- X PC=0x66;
- X NMI=0;
- X }
- X
- X/* if a RESET is pending, that has absolute priority */
- X
- X if (RESET)
- X {
- X INT=0; NMI=0; RESET=0; INT_FLAGS=0; PC=0;
- X }
- X
- X/* Now do a "refresh" cycle (really just increment low 7 bits of IR) */
- X
- X IR=(IR&0xff00)|((IR+1)&0x7f);
- SHAR_EOF
- echo "End of part 1"
- echo "File z80.c is continued in part 2"
- echo "2" > shar3_seq_.tmp
- exit 0
-
- --
- Nick Sayer | Disclaimer: "Don't try this at home, | RIP: Mel Blanc
- mrapple@quack.sac.ca.us | kids. This should only be done by | 1908-1989
- N6QQQ [44.2.1.17] | trained, professional idiots." | May he never
- 209-952-5347 (Telebit) | --Plucky Duck | be silenced.
-
-